home *** CD-ROM | disk | FTP | other *** search
- /* layout library.c -- Line Layout library routines.
-
- CHANGE LOG
-
- Date Person Action
- ---- ------ ------
-
- 900517 ERM • Created.
- 900702 ERM • Converted to new graphics-like interface.
- 900703 ERM • Add LineOptions parameter to SingleLayout guys.
- 900712 DGO • Fixed NewEasyLayout, which wasn't correctly doing LineOptions.
- 900731 DGO • Changed "line" to "lineOpts" throughout.
- • Added code to initialize controls in SetLayoutStyle if passed-in
- parameter "layoutControls" is nil.
- 900803 ERM • Removed controls initialization from NewSingleLayout.
- • Various other formatting clean-up.
- 900826 DGO • Added first cut at the paragraph functions.
- 900828 DGO • Fixed sense-of-sign bug. *BLUSH*
- 900912 ERM • Bagged references to hard-coded layout feature levels.
- 900914 ERM • Added GetStyleLayoutFeatureNames.
- 900917 ERM • THINK C 3.0 compatability changes.
- 910114 DGO • Removed overhangRect references.
- 910410 DGO • Merged Mike's changes to font manager.
- • Added lineHeight parameter to NewParagraph.
- 910415 ERM + DGO • Added include of ToolUtils.
- 910516 OWS • Converted to ANSI-style function declarations.
- • Updated includes for Think C 5.0.
- 910529 DGO • Changed to final 1.0 form.
- 910626 DGO • Bug fixing in NewParagraph (undisposed shape, bad pointer).
- 910820 DGO • Added NewDiscontiguousSelection function.
- • Minor name changes.
- 911118 ERM • Replaced GetStyleRunFeatureNames w/ GetStyleRunFeatureTypeNames, GetStyleRunFeatureSelectorNames.
- 911120 ERM • Removed gxRunFeatureType from RunFeatureSelectorName.
- 911124 DGO • Moved NewDiscontiguousSelection to selection library.
- 920309 ERM • GXNewLayout now has explicit run counts.
- 920505 DGO • Fixed NewStyledParagraph linebreaking bug.
- 930623 DGO • Added GXIgnoreGraphicsNotice for text_attributes_already_set.
-
- */
-
- /* Copyright ©1990-1993 Apple Computer, Inc. All rights reserved. */
-
- #include <Types.h>
- #include <Memory.h>
- #include <Resources.h>
- #include <ToolUtils.h>
-
- #include "graphics routines.h"
- #include "math routines.h"
- #include "layout types.h"
- #include "layout routines.h"
- #include "layout library.h"
- #include "font routines.h"
- #include "font library.h"
-
- void InitializeLayoutOptions (gxLayoutOptions *layoutOptions)
- { layoutOptions->width = 0;
- layoutOptions->flush = 0;
- layoutOptions->just = 0;
- layoutOptions->flags = 0;
- layoutOptions->baselineRec = nil;
- }
-
- void SetDefaultPriorityJustOverride (gxPriorityJustificationOverride *override)
- { short i;
- gxWidthDeltaRecord *pDelta;
-
- pDelta = override->deltas;
- for (i = 0; i < gxNumberOfJustificationPriorities; i++)
- { pDelta->growFlags = pDelta->shrinkFlags = 0;
- pDelta->beforeGrowLimit = pDelta->afterGrowLimit =
- pDelta->beforeShrinkLimit = pDelta->afterShrinkLimit = 0;
- pDelta++;
- } /* endloop i */
- }
-
- void InitializeRunControls (gxRunControls *runControls)
- { runControls->flags = 0;
- runControls->beforeWithStreamShift = runControls->afterWithStreamShift = 0;
- runControls->crossStreamShift = 0;
- runControls->imposedWidth = 0;
- runControls->track = 0;
- runControls->hangingInhibitFactor = runControls->kerningInhibitFactor = 0;
- runControls->baselineType = gxRomanBaseline;
- runControls->decompositionAdjustmentFactor = 0;
- }
-
- void InitializeStyleRunOverrides (StyleRunOverrides *overrides)
- { overrides->priorityJustOverride = nil;
- overrides->glyphJustOverrides = nil;
- overrides->glyphJustOverridesCount = 0;
- overrides->glyphSubstitutions = nil;
- overrides->glyphSubstitutionsCount = 0;
- overrides->kerningAdjustments = nil;
- overrides->kerningAdjustmentsCount = 0;
- }
-
- static void SetStyleNamedFont(gxStyle s, unsigned char* name)
- {
- gxFont fontID = FindPNameFont(gxFullFontName, name);
- if (fontID != GXGetStyleFont(s))
- GXSetStyleFont(s, fontID);
- }
-
- void SetLayoutStyle (
- gxStyle s,
- char *gxFontName,
- Fixed textSize,
- gxTextAttribute attr,
- gxRunControls *runControls,
- gxRunFeature runFeatures[],
- long runFeaturesCount,
- StyleRunOverrides *overrides)
- { gxRunControls localControls;
-
- #ifdef debugging
- GXIgnoreGraphicsNotice(attributes_already_set);
- GXIgnoreGraphicsNotice(text_attributes_already_set);
- #endif
-
- SetStyleNamedFont (s, (unsigned char*)gxFontName);
- GXSetStyleTextSize (s, textSize);
- GXSetStyleTextAttributes (s, attr);
-
- if (!runControls)
- { InitializeRunControls(&localControls);
- runControls = &localControls;
- }
-
- GXSetStyleRunControls (s, runControls);
-
- if (runFeatures) GXSetStyleRunFeatures (s, runFeaturesCount, runFeatures);
-
- if (overrides)
- { if (overrides->glyphSubstitutions)
- GXSetStyleRunGlyphSubstitutions (s, overrides->glyphSubstitutionsCount, overrides->glyphSubstitutions);
- if (overrides->kerningAdjustments)
- GXSetStyleRunKerningAdjustments (s, overrides->kerningAdjustmentsCount, overrides->kerningAdjustments);
- if (overrides->glyphJustOverrides)
- GXSetStyleRunGlyphJustOverrides (s, overrides->glyphJustOverridesCount, overrides->glyphJustOverrides);
- if (overrides->priorityJustOverride)
- GXSetStyleRunPriorityJustOverride (s, overrides->priorityJustOverride);
- }
- #ifdef debugging
- GXPopGraphicsNotice();
- GXPopGraphicsNotice();
- #endif
- }
-
- gxStyle NewLayoutStyle (
- char *gxFontName,
- Fixed textSize,
- gxTextAttribute attr,
- gxRunControls *runControls,
- gxRunFeature runFeatures[],
- long runFeaturesCount,
- StyleRunOverrides *overrides)
- { gxStyle newStyle = GXNewStyle ();
-
- SetLayoutStyle (
- newStyle,
- gxFontName,
- textSize,
- attr,
- runControls,
- runFeatures,
- runFeaturesCount,
- overrides);
-
- return (newStyle);
- }
-
- gxShape NewSingleLayout (
- char *text,
- char *gxFontName,
- Fixed textSize,
- gxLayoutOptions *options,
- gxPoint *position,
- gxTextAttribute attr,
- gxRunControls *runControls,
- gxRunFeature runFeatures[],
- long runFeaturesCount,
- StyleRunOverrides *overrides)
- { gxStyle newLayoutStyle;
- gxShape newLayoutShape;
- short len, level = 0;
- char *s;
-
- newLayoutStyle = NewLayoutStyle (
- gxFontName,
- textSize,
- attr,
- runControls,
- runFeatures,
- runFeaturesCount,
- overrides);
-
- for (len = 0, s = text; *s++ != 0; len++) ;
-
- newLayoutShape = GXNewLayout (
- 1,
- &len,
- (const void **) &text,
- 1,
- &len,
- &newLayoutStyle,
- 1,
- &len,
- &level,
- options,
- position);
-
- GXDisposeStyle (newLayoutStyle);
-
- return newLayoutShape;
- }
-
- /* NewParagraph is the simplest of the paragraph creation functions. It assumes a single
- gxStyle for the whole paragraph, and does its own deduction about where the paragraph
- ends (namely at a hard stop, CR or HT). */
-
- short CountBytes(char *text);
- short CountBytes(char *text)
- {
- short count = 0;
- while (*text != 13 && *text != 9)
- {text++; count++;}
- return count;
- } /* CountBytes */
-
- ParagraphRecordHandle NewParagraph(
- char *text,
- gxStyle baseStyle,
- Fixed width,
- long justified,
- Fixed lineHeight,
- gxPoint *firstOrigin)
- {
- /* Constants */
- #define extraLineGap ff(2)
- #define lineStartsCount 50
- /* Variables */
- boolean startIsStaked;
- gxByteOffset lineStarts[lineStartsCount], newLineStart, nextStake,
- nls2, priorStake, thisLineStart;
- char *pChar;
- Fixed currLineDelta, textSize;
- gxLayoutOptions options;
- ParagraphRecordHandle paraHandle;
- gxShape bigLayout, thisLine;
- short byteCount, i, level = 0, nextLineIndex;
-
- byteCount = CountBytes(text); /* doesn't count the CR or HT!! */
- bigLayout = GXNewLayout(
- 1,
- &byteCount,
- (const void **) &text,
- 1,
- &byteCount,
- &baseStyle,
- 1,
- &byteCount,
- &level,
- nil,
- firstOrigin);
-
- /* We next compute the gxLine breaks and store the offsets that correspond to them in a
- temporary array. */
-
- thisLineStart = 0;
- nextLineIndex = 0;
- while (thisLineStart < byteCount && nextLineIndex < lineStartsCount - 1)
- {
- lineStarts[nextLineIndex++] = thisLineStart;
- newLineStart = GXGetLayoutBreakOffset(
- bigLayout, thisLineStart, width, 0, nil, &startIsStaked, &priorStake, &nextStake);
- if (newLineStart == byteCount) break;
- /* Now backtrack to first prior space. */
- nls2 = newLineStart;
- pChar = text + newLineStart - 1;
- while (nls2 >= 0 && *pChar != ' ')
- {
- pChar--;
- nls2--;
- }
- if (nls2 < 0) thisLineStart = newLineStart;
- else thisLineStart = nls2;
- }
- lineStarts[nextLineIndex] = byteCount;
-
- /* Allocate space for the ParagraphRecord. */
-
- paraHandle = (ParagraphRecordHandle) NewHandle(
- (Size) (sizeof(ParagraphRecord) + nextLineIndex * sizeof(gxShape)));
- (*paraHandle)->nLayouts = nextLineIndex;
-
- /* Now create the layouts and place them in the ParagraphRecord. */
-
- InitializeLayoutOptions(&options);
- options.width = width;
- if (justified) options.just = fract1;
- textSize = GXGetStyleTextSize(baseStyle);
- currLineDelta = 0;
-
- for (i = 0; i < nextLineIndex; i++)
- {
- if (i == nextLineIndex - 1) options.just = 0; /* don't justify the last gxLine... */
- thisLine = GXNewLayoutFromRange(
- bigLayout, lineStarts[i], lineStarts[i+1], &options, nil);
- if (currLineDelta) GXMoveShape(thisLine, 0, currLineDelta);
- (*paraHandle)->layouts[i] = thisLine;
- currLineDelta += (lineHeight ? lineHeight : (textSize + extraLineGap));
- }
-
- (*paraHandle)->totalHeight = currLineDelta;
-
- GXDisposeShape(bigLayout);
- return paraHandle;
- } /* NewParagraph */
-
- static char *GetTextPiecePtr(
- const void *text[],
- const short textRunLengths[],
- short offset)
-
- {
- char **pPiece = (char **) text;
- short oCopy = offset;
- short *runLength = (short *) textRunLengths;
- while (oCopy > *runLength)
- {oCopy -= *runLength++; pPiece++;}
- return *pPiece + oCopy;
- } /* GetTextPiecePtr */
-
- static long GetPreviousOffset(gxShape layout, long offset)
- { unsigned short firstGlyph, secondGlyph;
- gxLayoutOffsetState offsetState;
- static long offsetStateSizes[] = {1, 1, 2, 2, 0};
-
- GXGetOffsetGlyphs(layout, offset, 0, &offsetState, &firstGlyph, &secondGlyph);
-
- return offset - offsetStateSizes[offsetState & ~gxOffsetInsideLigature];
- }
-
- static long GetNextOffset(gxShape layout, long offset)
- { unsigned short firstGlyph, secondGlyph;
- gxLayoutOffsetState offsetState;
- static long offsetStateSizes[] = {1, 2, 1, 2, 0};
-
- GXGetOffsetGlyphs(layout, offset, 0, &offsetState, &firstGlyph, &secondGlyph);
-
- return offset + offsetStateSizes[offsetState & ~gxOffsetInsideLigature];
- }
-
- ParagraphRecordHandle NewStyledParagraph(
- long textRunCount,
- const void *text[],
- const short textRunLengths[],
- long styleRunCount,
- const gxStyle styles[],
- const short styleRunLengths[],
- long levelRunCount,
- const short levels[],
- const short levelRunLengths[],
- long totalByteCount,
- const gxLayoutOptions *layoutOptions,
- Fixed lineHeight,
- const gxPoint *firstOrigin)
- {
- /* Variables */
- boolean startIsStaked;
- gxByteOffset lineStarts[lineStartsCount], newLineStart, nextStake,
- nls2, priorStake, thisLineStart;
- char *pChar, *pSav;
- Fixed currLineDelta, lineAscent, lineDescent;
- gxLayoutOptions specialOptions;
- ParagraphRecordHandle paraHandle;
- gxShape bigLayout, thisLine;
- short i, level = 0, nextLineIndex;
-
- specialOptions = *layoutOptions;
- specialOptions.just = specialOptions.flush = 0;
- specialOptions.width = 0;
-
- bigLayout = GXNewLayout(
- textRunCount,
- textRunLengths,
- text,
- styleRunCount,
- styleRunLengths,
- styles,
- levelRunCount,
- levelRunLengths,
- levels,
- &specialOptions,
- firstOrigin);
-
- /* We next compute the gxLine breaks and store the offsets that correspond to them in a
- temporary array. */
-
- thisLineStart = 0;
- nextLineIndex = 0;
- while (thisLineStart < totalByteCount && nextLineIndex < lineStartsCount - 1)
- {
- lineStarts[nextLineIndex++] = thisLineStart;
- newLineStart = GXGetLayoutBreakOffset(
- bigLayout,
- thisLineStart,
- layoutOptions->width,
- 0,
- nil,
- &startIsStaked,
- &priorStake,
- &nextStake);
- if (newLineStart == totalByteCount) break;
- /* Now backtrack to first prior space. */
- nls2 = newLineStart;
- pSav = pChar = GetTextPiecePtr(text, textRunLengths, GetPreviousOffset(bigLayout, newLineStart));
- while (nls2 >= lineStarts[nextLineIndex-1] && *pChar != ' ')
- pChar = GetTextPiecePtr(text, textRunLengths, nls2 = GetPreviousOffset(bigLayout, nls2));
-
- if (nls2 <= lineStarts[nextLineIndex-1]) thisLineStart = newLineStart;
- else
- {
- if (pSav != pChar) nls2 = GetNextOffset(bigLayout, nls2);
- thisLineStart = nls2;
- }
- }
- lineStarts[nextLineIndex] = (short) totalByteCount;
-
- /* Allocate space for the ParagraphRecord. */
-
- paraHandle = (ParagraphRecordHandle) NewHandle(
- (Size) (sizeof(ParagraphRecord) + nextLineIndex * sizeof(gxShape)));
- (*paraHandle)->nLayouts = nextLineIndex;
-
- /* Now create the layouts and place them in the ParagraphRecord. */
-
- specialOptions = *layoutOptions;
- currLineDelta = 0;
-
- for (i = 0; i < nextLineIndex; i++)
- {
- if (i == nextLineIndex - 1) specialOptions.just = 0; /* don't justify last gxLine... */
- thisLine = GXNewLayoutFromRange(
- bigLayout, lineStarts[i], lineStarts[i+1], &specialOptions, nil);
- if (currLineDelta) GXMoveShape(thisLine, 0, currLineDelta);
- (*paraHandle)->layouts[i] = thisLine;
- if (lineHeight) currLineDelta += lineHeight;
- else
- {
- GXGetLayoutSpan(thisLine, &lineAscent, &lineDescent);
- currLineDelta += lineAscent + lineDescent + extraLineGap;
- }
- }
-
- (*paraHandle)->totalHeight = currLineDelta;
-
- GXDisposeShape(bigLayout);
- return paraHandle;
- } /* NewStyledParagraph */
-
- /* DisposeParagraph disposes of the memory associated with a paragraph. While currently
- simple, it could be more involved if the paragraph itself retains more information. */
-
- void DisposeParagraph(ParagraphRecordHandle paraRec)
- {
- short i;
- for (i = 0; i < (*paraRec)->nLayouts; i++)
- GXDisposeShape((*paraRec)->layouts[i]);
- DisposeHandle((Handle) paraRec);
- } /* DisposeParagraph */
-
- /* GetLayoutBounds returns a gxShape corresponding to the bounds of the specified layout. It
- differs from GXGetShapeBounds in two respects: first, it returns a gxShape (rather than just
- a gxRectangle); and second, it takes both the layout's position and its gxMapping into account
- (GXGetShapeBounds only takes the layout's position into account). */
-
- gxShape GetLayoutBounds(gxShape layout)
- {
- gxMapping thisMapping;
- gxRectangle thisRect;
- gxShape rectShape;
-
- GXGetShapeBounds(layout, 0, &thisRect);
- rectShape = GXNewRectangle(&thisRect);
- #if 0
- GXIgnoreGraphicsNotice(transform_already_set);
- GXSetShapeTransform(rectShape, GXGetShapeTransform(layout));
- GXPopGraphicsNotice();
- #else
- GXMapShape(rectShape, GXGetTransformMapping(GXGetShapeTransform(layout), &thisMapping));
- #endif
- return rectShape;
- } /* GetLayoutBounds */
-